24  Human Impact and Mitigation

24.1 Essential Question

How can individuals, communities, and nations reduce their environmental impact?

24.2 Current U.S. Air Quality (Live)

Use this live bubble map to explore current particulate pollution (PM2.5) readings across the United States. Larger, darker circles indicate higher concentrations.

(a) Interactive 3D model of a volcanic crater.
(b)
Figure 24.1
Figure 24.2: Interactive Wind Rose: Frequency of wind speed and direction.
Figure 24.3: Composite Climate Risk Index by US County (Simulated)
Code
import plotly.graph_objects as go
import pandas as pd
import numpy as np
from urllib.request import urlopen
import json

# Load US county boundaries (GeoJSON)
with urlopen('https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json') as response:
    counties_geojson = json.load(response)

# Generate county-level climate threat data
# This creates realistic patterns based on geographic regions
np.random.seed(42)

# State-level threat patterns (primary threats and their probabilities)
state_patterns = {
    '01': {'threats': ['Hurricane', 'Tornado', 'Flooding'], 'weights': [0.5, 0.3, 0.2]},
    '04': {'threats': ['Extreme Heat', 'Drought', 'Wildfire'], 'weights': [0.5, 0.3, 0.2]},
    '05': {'threats': ['Tornado', 'Flooding', 'Extreme Heat'], 'weights': [0.4, 0.4, 0.2]},
    '06': {'threats': ['Wildfire', 'Drought', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '08': {'threats': ['Drought', 'Wildfire', 'Extreme Heat'], 'weights': [0.45, 0.35, 0.2]},
    '09': {'threats': ['Flooding', 'Winter Storm', 'Hurricane'], 'weights': [0.45, 0.35, 0.2]},
    '10': {'threats': ['Flooding', 'Hurricane', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '11': {'threats': ['Flooding', 'Extreme Heat', 'Winter Storm'], 'weights': [0.5, 0.3, 0.2]},
    '12': {'threats': ['Hurricane', 'Extreme Heat', 'Flooding'], 'weights': [0.6, 0.25, 0.15]},
    '13': {'threats': ['Hurricane', 'Extreme Heat', 'Tornado'], 'weights': [0.5, 0.3, 0.2]},
    '15': {'threats': ['Wildfire', 'Hurricane', 'Drought'], 'weights': [0.4, 0.35, 0.25]},
    '16': {'threats': ['Wildfire', 'Drought', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '17': {'threats': ['Flooding', 'Tornado', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '18': {'threats': ['Flooding', 'Tornado', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '19': {'threats': ['Flooding', 'Tornado', 'Drought'], 'weights': [0.5, 0.3, 0.2]},
    '20': {'threats': ['Drought', 'Tornado', 'Extreme Heat'], 'weights': [0.45, 0.35, 0.2]},
    '21': {'threats': ['Flooding', 'Tornado', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '22': {'threats': ['Hurricane', 'Flooding', 'Extreme Heat'], 'weights': [0.6, 0.25, 0.15]},
    '23': {'threats': ['Winter Storm', 'Flooding', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '24': {'threats': ['Flooding', 'Hurricane', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '25': {'threats': ['Flooding', 'Winter Storm', 'Hurricane'], 'weights': [0.45, 0.35, 0.2]},
    '26': {'threats': ['Flooding', 'Winter Storm', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '27': {'threats': ['Flooding', 'Winter Storm', 'Tornado'], 'weights': [0.45, 0.35, 0.2]},
    '28': {'threats': ['Hurricane', 'Flooding', 'Tornado'], 'weights': [0.5, 0.3, 0.2]},
    '29': {'threats': ['Flooding', 'Tornado', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '30': {'threats': ['Wildfire', 'Drought', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '31': {'threats': ['Drought', 'Tornado', 'Flooding'], 'weights': [0.45, 0.35, 0.2]},
    '32': {'threats': ['Drought', 'Extreme Heat', 'Wildfire'], 'weights': [0.5, 0.3, 0.2]},
    '33': {'threats': ['Winter Storm', 'Flooding', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '34': {'threats': ['Flooding', 'Hurricane', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '35': {'threats': ['Drought', 'Wildfire', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '36': {'threats': ['Flooding', 'Winter Storm', 'Hurricane'], 'weights': [0.45, 0.35, 0.2]},
    '37': {'threats': ['Hurricane', 'Flooding', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '38': {'threats': ['Drought', 'Flooding', 'Extreme Heat'], 'weights': [0.45, 0.35, 0.2]},
    '39': {'threats': ['Flooding', 'Tornado', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '40': {'threats': ['Drought', 'Tornado', 'Extreme Heat'], 'weights': [0.45, 0.35, 0.2]},
    '41': {'threats': ['Wildfire', 'Flooding', 'Drought'], 'weights': [0.5, 0.3, 0.2]},
    '42': {'threats': ['Flooding', 'Winter Storm', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '44': {'threats': ['Flooding', 'Hurricane', 'Winter Storm'], 'weights': [0.5, 0.3, 0.2]},
    '45': {'threats': ['Hurricane', 'Flooding', 'Extreme Heat'], 'weights': [0.6, 0.25, 0.15]},
    '46': {'threats': ['Drought', 'Extreme Heat', 'Flooding'], 'weights': [0.5, 0.3, 0.2]},
    '47': {'threats': ['Flooding', 'Tornado', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '48': {'threats': ['Extreme Heat', 'Drought', 'Hurricane'], 'weights': [0.4, 0.35, 0.25]},
    '49': {'threats': ['Drought', 'Wildfire', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '50': {'threats': ['Winter Storm', 'Flooding', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '51': {'threats': ['Flooding', 'Hurricane', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '53': {'threats': ['Wildfire', 'Flooding', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '54': {'threats': ['Flooding', 'Winter Storm', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '55': {'threats': ['Flooding', 'Winter Storm', 'Tornado'], 'weights': [0.45, 0.35, 0.2]},
    '56': {'threats': ['Drought', 'Wildfire', 'Extreme Heat'], 'weights': [0.5, 0.3, 0.2]},
    '72': {'threats': ['Hurricane', 'Extreme Heat', 'Flooding'], 'weights': [0.7, 0.2, 0.1]},
}

# Create county-level data from GeoJSON features
counties_data = []
for feature in counties_geojson['features']:
    fips = feature['id']
    state_fips = fips[:2]
    
    # Assign threat based on state pattern
    if state_fips in state_patterns:
        pattern = state_patterns[state_fips]
        threat = np.random.choice(pattern['threats'], p=pattern['weights'])
    else:
        threat = 'Flooding'  # Default for territories/other
    
    counties_data.append({
        'fips': fips,
        'threat': threat
    })

df = pd.DataFrame(counties_data)

# Define color mapping (colorblind-friendly palette)
color_map = {
    'Wildfire': '#d62728',       # Red
    'Hurricane': '#1f77b4',      # Blue  
    'Flooding': '#17becf',       # Cyan
    'Drought': '#bcbd22',        # Yellow-brown
    'Extreme Heat': '#ff7f0e',   # Orange
    'Tornado': '#9467bd',        # Purple
    'Winter Storm': '#7f7f7f'    # Gray
}

# Create the choropleth map
fig = go.Figure(go.Choroplethmapbox(
    geojson=counties_geojson,
    locations=df['fips'],
    z=df['threat'].map({threat: i for i, threat in enumerate(color_map.keys())}),
    colorscale=[[i/(len(color_map)-1), color] for i, color in enumerate(color_map.values())],
    text=df['threat'],
    hovertemplate='<b>County FIPS: %{location}</b><br>' +
                  'Primary Threat: %{text}<br>' +
                  '<extra></extra>',
    marker_opacity=0.8,
    marker_line_width=0.5,
    marker_line_color='white',
    showscale=False
))

# Add custom legend
for i, (threat, color) in enumerate(color_map.items()):
    count = (df['threat'] == threat).sum()
    fig.add_trace(go.Scattermapbox(
        lon=[0], lat=[0],
        mode='markers',
        marker=dict(size=10, color=color),
        name=f'{threat} ({count})',
        showlegend=True,
        hoverinfo='skip'
    ))

# Update layout
fig.update_layout(
    title={
        'text': 'Primary Climate Threats by U.S. County<br><sub>Based on Regional Climate Risk Patterns</sub>',
        'x': 0.5,
        'xanchor': 'center',
        'font': {'size': 22, 'color': '#2c3e50'}
    },
    mapbox=dict(
        style='carto-positron',
        zoom=3,
        center=dict(lat=38, lon=-96)
    ),
    font=dict(size=12, family='Arial, sans-serif'),
    legend=dict(
        title=dict(text='Climate Threat', font=dict(size=14, color='#2c3e50')),
        orientation='v',
        yanchor='middle',
        y=0.5,
        xanchor='left',
        x=1.02,
        bgcolor='rgba(255,255,255,0.9)',
        bordercolor='#cccccc',
        borderwidth=1
    ),
    margin=dict(l=0, r=150, t=80, b=0),
    width=1200,
    height=700
)

fig
Figure 24.4: Primary Climate Threats by U.S. County

24.2.1 ✅ Quick Analysis

  1. Where are the highest PM2.5 readings clustered today?
  2. Which regions show lower PM2.5 values?
  3. What local factors might explain these patterns?